package com.gitee.wsl.jvm.okhttp.intercept.updown

import com.gitee.wsl.jvm.okhttp.listener.ProgressListener
import okhttp3.*
import okio.*


/**
 * 拦截器，加入进度监听
 *
 */
class ProgressDownLoadInterceptor(private val listener: ProgressListener) : Interceptor {

    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        val originalResponse: Response = chain.proceed(chain.request())
        val progressBody: ResponseBody? = originalResponse.body?.let { ProgressResponseBody(it, listener) }
        return originalResponse.newBuilder().body(progressBody).build()
    }
}

class ProgressUpLoadInterceptor(private val listener: ProgressListener) : Interceptor {
    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        val originalRequest: Request = chain.request()
        if (originalRequest.body == null) {
            return chain.proceed(originalRequest)
        }
        val listenerRequest= RequestProgressBody(originalRequest.body!!,listener)
        val compressedRequest = originalRequest.newBuilder().post(listenerRequest).build()
        return chain.proceed(compressedRequest)
    }
}

internal class ProgressResponseBody(
    private val responseBody: ResponseBody,
    private val  listener: ProgressListener?
) : ResponseBody() {
    private var bufferedSource: BufferedSource? = null

    override fun contentType(): MediaType? {
        return responseBody.contentType()
    }

    override fun contentLength(): Long {
        return responseBody.contentLength()
    }

    override fun source(): BufferedSource {
        if (bufferedSource == null) {
            bufferedSource = source(responseBody.source()).buffer()
        }
        return bufferedSource as BufferedSource
    }

    private fun source(source: Source): Source {
        return object : ForwardingSource(source) {
            private var totalReadBytes: Long = 0

            @Throws(IOException::class)
            override fun read(sink: Buffer, byteCount: Long): Long {
                val readBytes = super.read(sink, byteCount)
                totalReadBytes += if (readBytes != -1L) readBytes else 0
                if (totalReadBytes > 0 && contentLength() > 0 && listener != null) {
                    listener.onProgress(totalReadBytes, responseBody.contentLength())
                }
                return readBytes
            }
        }
    }
}

class RequestProgressBody(
    private val requestBody: RequestBody,
    private val uploadProgressListener: ProgressListener?
) : RequestBody() {
    private var bufferedSink: BufferedSink? = null

    override fun contentType(): MediaType? {
        return requestBody.contentType()
    }

    @Throws(IOException::class)
    override fun contentLength(): Long {
        return requestBody.contentLength()
    }

    @Throws(IOException::class)
    override fun writeTo(sink: BufferedSink) {
        if (bufferedSink == null) {
            bufferedSink = sink(sink).buffer()
        }
        requestBody.writeTo(bufferedSink!!)
        bufferedSink!!.flush()
    }

    private fun sink(sink: Sink): Sink {
        return object : ForwardingSink(sink) {
            var bytesWritten = 0L
            var contentLength = 0L
            @Throws(IOException::class)
            override fun write(source: Buffer, byteCount: Long) {
                super.write(source, byteCount)
                if (contentLength == 0L) {
                    contentLength = contentLength()
                }
                bytesWritten += byteCount
                if (contentLength > 0  && uploadProgressListener != null) {
                    uploadProgressListener.onProgress(contentLength, bytesWritten)
                }
             }
        }

    }
}